package com.yeyks.commonReference.service.consumer.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.comparator.CompareUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeyks.account.dal.domain.AccountInfo;
import com.yeyks.common.ajax.AjaxResponseBody;
import com.yeyks.common.base.Arguments;
import com.yeyks.common.constants.AccountType;
import com.yeyks.common.constants.ConfigKey;
import com.yeyks.common.constants.activity.RedisKeyPreConstant;
import com.yeyks.common.dto.CashOutOrderDTO;
import com.yeyks.common.dto.JsonPayAccount;
import com.yeyks.common.em.*;
import com.yeyks.common.em.consumer.UserInviteRelationTypeEnum;
import com.yeyks.common.em.pay.PayTypeEnum;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.param.CashOutDownloadParam;
import com.yeyks.common.param.CashOutQueryParam;
import com.yeyks.common.result.CashOutDownloadResult;
import com.yeyks.common.utils.*;
import com.yeyks.commonReference.append.sms.SmsService;
import com.yeyks.commonReference.append.wxPay.service.WeiXinPayService;
import com.yeyks.commonReference.service.account.AccountInfoService;
import com.yeyks.commonReference.service.config.ConfigService;
import com.yeyks.commonReference.service.consumer.CashOutOrderService;
import com.yeyks.consumer.dal.dao.*;
import com.yeyks.consumer.dal.domain.*;
import com.yeyks.consumer.param.CashOutOrderExtractParam;
import com.yeyks.consumer.param.UserAccountOverview.UserAccountOverviewinvitedAmountParam;
import com.yeyks.consumer.service.UserAccountOverviewService;
import com.yeyks.consumer.service.UserInfoService;
import com.yeyks.consumer.service.UserWxidRelationService;
import com.yeyks.consumer.vo.UserAccountOverviewWithdrawalInquiryVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;


/**
 * <p>
 * 用户提现订单表 服务实现类
 * </p>
 *
 * @author yun
 * @since 2019-06-25
 */
@Service
@Slf4j
public class CashOutOrderServiceImpl extends ServiceImpl<CashOutOrderMapper, CashOutOrder> implements CashOutOrderService {

    @Autowired
    private CashOutOrderMapper cashOutOrderMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private AccountInfoService accountService;

    @Autowired
    private UserBillMapper userBillMapper;

    @Autowired
    private UserAccountOverviewMapper userAccountOverviewMapper;

    @Autowired
    private SmsService smsService;

    @Autowired
    private UserAccountOverviewService userAccountOverviewService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private WeiXinPayService weiXinPayService;
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserInviteRelationMapper userInviteRelationMapper;
    @Autowired
    private UserWxidRelationService userWxidRelationService;


    @Override
    public ResponseEntity<AjaxResponseBody> queryList(CashOutQueryParam param, Integer pageNum, Integer pageSize) {

        AjaxResponseBody responseBody = new AjaxResponseBody();

        try {
            AccountInfo operatorInfo = accountService.token2AccountInfo(param.getToken());
            log.info("当前操作人" + operatorInfo.getUsername());

            if (pageNum == null || pageNum == 0) {
                pageNum = 1;
            }
            Map<String, Object> resultMap = Maps.newHashMap();
            List<CashOutOrderDTO> cashOutOrderDTOList = Lists.newArrayList();
            int count = cashOutOrderMapper.selectByPageCountV2(param);
            resultMap.put("count", count);
            List<CashOutOrder> cashOutOrderList = cashOutOrderMapper.selectByPageV2(param, ((pageNum - 1) * pageSize), pageSize);
            if (!CollectionUtils.isEmpty(cashOutOrderList)) {
                cashOutOrderDTOList = ObjectConvertUtil.convertList(cashOutOrderList, CashOutOrderDTO.class);
                //更新其他数据信息
                this.convertOtherDTO(cashOutOrderDTOList);
            }
            resultMap.put("list", cashOutOrderDTOList);
            responseBody.setBody(resultMap);
            responseBody.setCode(ResponseStatus.RS_SUCCESS.getCode());
            responseBody.setMsg(ResponseStatus.RS_SUCCESS.getMsg());
        } catch (Throwable e) {
            responseBody.setCode(ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }
        return ResponseEntity.ok(responseBody);
    }

    private List<CashOutOrderDTO> convertOtherDTO(List<CashOutOrderDTO> cashList) {

        if (!CollectionUtils.isEmpty(cashList)) {
            cashList.forEach(cashOutOrderDTO -> {
                UserInfo userInfo = userInfoMapper.selectByPrimaryKey(cashOutOrderDTO.getUserId());
                if (null != userInfo && null != userInfo.getPayAccount() && !"".equals(userInfo.getPayAccount())) {
                    JsonPayAccount pay = JSONObject.parseObject(userInfo.getPayAccount(), JsonPayAccount.class);
                    if (null != pay) {
                        cashOutOrderDTO.setBankCard(pay.getBankCard());
                        cashOutOrderDTO.setBankName(pay.getBankName());
                        cashOutOrderDTO.setUserName(pay.getUserName());
                        cashOutOrderDTO.setBranchName(pay.getBranchName());
                    }
                }
                if(null!=userInfo)
                {
                    //查询用户邀请其他用户的数量
                    QueryWrapper<UserInviteRelation> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq(UserInviteRelation.PARENT_ID,userInfo.getId())
                    .in(UserInviteRelation.TYPE, Lists.newArrayList(UserInviteRelationTypeEnum.PROMOTION.getValue(),
                            UserInviteRelationTypeEnum.MAKER.getValue()));
                    cashOutOrderDTO.setInviteCount(userInviteRelationMapper.selectCount(queryWrapper));
                }
            });
        }
        return cashList;
    }

    @Override
    @Transactional
    public ResponseEntity<AjaxResponseBody> confirmMoney(String token, Long id, String ip) {

        AjaxResponseBody responseBody = new AjaxResponseBody();

        try {
            AccountInfo operatorInfo = accountService.token2AccountInfo(token);
            log.info("当前操作人" + operatorInfo.getName());

            CashOutOrder cashOutOrder = cashOutOrderMapper.selectByPrimaryKey(id);
            int count = 0;
            if (null != cashOutOrder && cashOutOrder.getStatus() == CashOutStatusEnum.TO_BE_AUDITED.getCode()) {
                cashOutOrder.setStatus(CashOutStatusEnum.SUCCESS.getCode()); //审核通过
                cashOutOrder.setAuditId(operatorInfo.getId());
                cashOutOrder.setAuditTime(new Date());
                count = cashOutOrderMapper.updateByPrimaryKeySelective(cashOutOrder);
            }
            if (count > 0) {
                responseBody.setCode(ResponseStatus.RS_SUCCESS.getCode());
                //微信提现
                if (cashOutOrder.getType().equals(2)) {
                    //直接打款
                    if (!weiXinPayService.disposeWxExtract(cashOutOrder.getOrderNo(), cashOutOrder.getOpenId(), cashOutOrder.getAmount(), ip, PayTypeEnum.WXPAY.desc())) {
                        cashOutOrder.setStatus(CashOutStatusEnum.FAILED.getCode());
                        baseMapper.updateById(cashOutOrder);
                        throw new ServiceException("打款失败");
                    }
                }
                responseBody.setMsg("确认审核提现成功");
            } else {
                responseBody.setCode(ResponseStatus.RS_FAIL.getCode());
                responseBody.setMsg("审核失败");
            }
        } catch (ServiceException e) {
            throw new ServiceException(e.getMessage());
        } catch (Throwable e) {
            responseBody.setCode(ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }
        return ResponseEntity.ok(responseBody);
    }

    @Override
    @Transactional
    public ResponseEntity<AjaxResponseBody> refundMoney(String token, Long id, String remark) {
        AjaxResponseBody responseBody = new AjaxResponseBody();

        try {
            AccountInfo operatorInfo = accountService.token2AccountInfo(token);
            log.info("当前操作人" + operatorInfo.getName());
            CashOutOrder cashOutOrder = cashOutOrderMapper.selectByPrimaryKey(id);
            int count = 0;
            if (null != cashOutOrder && cashOutOrder.getStatus() == CashOutStatusEnum.TO_BE_AUDITED.getCode()) {
                cashOutOrder.setStatus(CashOutStatusEnum.FAILED.getCode()); //取消审核，退回
                cashOutOrder.setAuditId(operatorInfo.getId());
                cashOutOrder.setAuditTime(new Date());
                cashOutOrder.setRemark(remark);
                count = cashOutOrderMapper.updateByPrimaryKeySelective(cashOutOrder);
            }
            if (count > 0) {
                //返回到用户资金的余额中
                updateAddUserBill(cashOutOrder);
                responseBody.setCode(ResponseStatus.RS_SUCCESS.getCode());
                responseBody.setMsg("取消审核成功");
                //发送短信
                log.info("开始发送打款失败短信:" + cashOutOrder.getPhone());
                smsService.sendSmsForCashOutFail(cashOutOrder.getPhone());
//                smsService.sendSmsForCashOutFailReason(cashOutOrder.getPhone(), remark);

            }
        } catch (Throwable e) {
            responseBody.setCode(ResponseStatus.RS_FAIL.getCode());
            responseBody.setMsg(e.getMessage());
        }
        return ResponseEntity.ok(responseBody);
    }

    @Transactional
    public void updateAddUserBill(CashOutOrder cashOutOrder) {
        //得到用户当前余额
        UserAccountOverview userAccountOverview = userAccountOverviewMapper.selectByUserIdAndType(cashOutOrder.getUserId(), cashOutOrder.getAmountType());
        UserBill userBill = new UserBill();
        userBill.setType(UserBillEnum.CASH_OUT.getCode());
        userBill.setRemark(UserBillEnum.CASH_OUT.getMsg());
        userBill.setAvaliableAmount((long) (userAccountOverview.getRemainAmount() + cashOutOrder.getAmount()));
        userBill.setCreateTime(new Date());
        userBill.setOperatorAmount(Long.valueOf(cashOutOrder.getAmount()));
        userBill.setUserId(Long.valueOf(cashOutOrder.getUserId()));
        //添加操作的信息
        userBillMapper.insertSelective(userBill);
        //修改用户余额
        userAccountOverview.setRemainAmount(userAccountOverview.getRemainAmount() + cashOutOrder.getAmount());
        //支出修改
        userAccountOverview.setOutAmount(userAccountOverview.getOutAmount() - cashOutOrder.getAmount());
        userAccountOverviewMapper.updateByPrimaryKeySelective(userAccountOverview);
    }

    /**
     * 获取指定用户最新的提现记录
     *
     * @param userId
     * @return
     */
    @Override
    public CashOutOrder getNewestCashOutOrder(Integer userId) {
        return baseMapper.getNewestCashOutOrder(userId);
    }

    /**
     * 我的佣金页面
     *
     * @return
     */
//    @Override
//    public AccountOverviewDTO info(UserInfo userInfo) {
//        AccountOverviewDTO overviewDTO = new AccountOverviewDTO();
//        overviewDTO.setFlag(false);
//        overviewDTO.setRemainAmount(0);
//        overviewDTO.setStatus(null);
//        overviewDTO.setOverAmount(getOverAmount());
//        UserAccountOverviewDTO info = userAccountOverviewService.info(userInfo);
//        if (info == null) {
//            return overviewDTO;
//        }
//        overviewDTO.setRemainAmount(info.getRemainAmount());
//        //首先判断是否有提现中的记录，有的话直接status = 1(提现中)，flag = false，
//        // 没有记录才判断今天是否已提现
//        CashOutOrder cash = getNewestCashOutOrder(userInfo.getId());
//        if (cash == null) {
//            overviewDTO.setFlag(true);
//            return overviewDTO;
//        }
//        if (cash.getStatus() != null
//                && cash.getStatus().equals(CashOutOrderStatus.pre_check.value())) {
//            overviewDTO.setStatus(cash.getStatus());
//            return overviewDTO;
//        }
//        Date orderDate = cash.getGmtCreate();
//        if (orderDate == null) {
//            overviewDTO.setFlag(true);
//            return overviewDTO;
//        }
//        Date newBeginDate = DateUtils.dayBegin(0);
//        //当前已提现过
//        if (DateUtils.dateCompareDate(orderDate, newBeginDate)) {
//            overviewDTO.setFlag(false);
//        } else {
//            overviewDTO.setFlag(true);
//        }
//        return overviewDTO;
//    }

    private Integer getOverAmount() {
        try {
            String value = configService.getValue(ConfigKey.EXTRACT_OVER_AMOUNT);
            if (ArgumentsCheckUtil.strIsNull(value)) {
                return 5000;
            }
            return Integer.valueOf(value);
        } catch (Exception e) {
            log.error("获取用户提现满减金额异常", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return 5000;
    }

    /**
     * 用户提现(银行卡)
     *
     * @return
     */
//    @Override
//    @Transactional
//    public Boolean extract(UserInfo userInfo, Integer amount) {
//
//        AccountOverviewDTO info = info(userInfo);
//        if (info.getStatus() != null && info.getStatus().equals(1)) {
//            throw new ServiceException("您有提现中的订单");
//        }
//        if (!info.getFlag()) {
//            throw new ServiceException("您今天已提现过了");
//        }
//        //提现，用户余额减少
//        if (userAccountOverviewService.descAmount(amount, userInfo.getId(), UserBillType.WITHDRAW.value(), UserBillType.WITHDRAW.desc())) {
//            CashOutOrder cashOutOrder = getCashOutOrder(userInfo, amount);
//            return baseMapper.insert(cashOutOrder) == 1;
//        }
//        return false;
//    }

    //创客提现的金额列表
    ArrayList<Integer> CHUANG_KE_JIN_E = CollectionUtil.newArrayList(5000,10000,50000,100000);

    //提现
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean extract(CashOutOrderExtractParam param) {
        if (Objects.equals(param.getAmountType(), 2) && !CollectionUtil.contains(CHUANG_KE_JIN_E, param.getAmount())) {
            throw new ServiceException("提现金额有误");
        }
        return redisUtil.runWithLock(RedisKeyPreConstant.CASH_OUT_ORDER_EXTRACT + param.getUserId(), () -> {
            Integer amount = param.getAmount();
            UserInfo userInfo = userInfoService.getById(param.getUserId());
            if (Objects.isNull(userInfo)) {
                throw new ServiceException("用户不存在");
            }
            switch (param.getType()) {
                case 1:
                    if (userInfoService.isBind(userInfo)) {
                        throw new ServiceException("您未绑定银行卡，请先去绑卡");
                    }
                    break;
                case 2:
                    UserWxidRelation userWxidRelation = userWxidRelationService.getByUserId(param.getUserId());
                    if (Objects.isNull(userWxidRelation)) {
                        throw new ServiceException("没有绑定微信");
                    }
                    param.setOpenId(userWxidRelation.getOpenId());
                    if((CompareUtil.compare(amount,30) < 0) || (CompareUtil.compare(100000,amount) < 0)){
                        throw new ServiceException("付款金额超出限制:低于最小金额0.30元或累计超过1000.00元");
                    }
                    break;
                default:
                    throw new ServiceException("类型错误");
            }
            UserAccountOverviewWithdrawalInquiryVo info = userAccountOverviewService.invitedAmount(new UserAccountOverviewinvitedAmountParam().setUserId(param.getUserId()).setType(param.getAmountType()));
            if (info.getStatus() != null && info.getStatus().equals(1)) {
                throw new ServiceException("您有提现中的订单");
            }
            if (!info.getFlag()) {
                throw new ServiceException("您今天已提现过了");
            }
            //提现，用户余额减少
            if (userAccountOverviewService.descAmount(amount, userInfo.getId(), UserBillType.WITHDRAW.value(), UserBillType.WITHDRAW.desc(),param.getAmountType())) {
                CashOutOrder cashOutOrder = new CashOutOrder();
                cashOutOrder.setAmount(amount);
                cashOutOrder.setAuditId(null);//审核人
                cashOutOrder.setAuditTime(null);//审核时间
                cashOutOrder.setDeleteFlag(0);//0；未删除  1：已删除
                cashOutOrder.setOrderNo(IdWorkerUtil.nextStrId());//订单号
                cashOutOrder.setStatus(1);//1待审核，2审核通过，3 审核未通过，4 失败
                cashOutOrder.setUserId(userInfo.getId());
                cashOutOrder.setPhone(userInfo.getPhone());
                Date date = new Date();
                cashOutOrder.setGmtCreate(date);
                cashOutOrder.setGmtModified(date);
                cashOutOrder.setType(param.getType());
                cashOutOrder.setOpenId(param.getOpenId());
                cashOutOrder.setAmountType(param.getAmountType());
                if(!save(cashOutOrder)){
                    throw new ServiceException("提现记录存储失败");
                }
            }
            return true;
        });
    }

    /**
     * 提现常见问题
     *
     * @return
     */
    @Override
    public Object problem() {
        try {
            String value = configService.getValue(ConfigKey.EXTRACT_PROBLEM);
            return JSONObject.parseObject(value);

        } catch (Exception e) {
            log.error("提现常见问题异常{}", e.getLocalizedMessage());
            e.printStackTrace();
            return getDefault();
        }
    }

    /**
     * 导出订单
     *
     * @param loginUser
     * @param param
     * @return
     */
    @Override
    public List<CashOutDownloadResult> selectDownloadOrder(AccountInfo loginUser, CashOutDownloadParam param) {
        if (AccountType.Administrator != loginUser.getType()) {
            throw new ServiceException("当前用户无权访问");
        }
        List<CashOutOrder> cashOutOrders = baseMapper.selectList(new QueryWrapper<CashOutOrder>()
                .eq(CashOutOrder.DELETE_FLAG, 0)
                .in(CashOutOrder.AMOUNT_TYPE, Splitters.splitToInteger(param.getAmountType(), Splitters.COMMA))
                .between(CashOutOrder.GMT_CREATE, new Date(param.getStartTime()), new Date(param.getEndTime()))
                .orderByDesc(CashOutOrder.GMT_CREATE));
        if (null == cashOutOrders) {
            return Lists.newArrayList();
        }
        return getCashOutDownloadResult(cashOutOrders);
    }

    private List<CashOutDownloadResult> getCashOutDownloadResult(List<CashOutOrder> cashOutOrders) {
        List<CashOutDownloadResult> results = Lists.newArrayList();
        Map<Integer, UserInfo> userInfoMap = getUserInfoMap(cashOutOrders);
        cashOutOrders.forEach(e -> {
            CashOutDownloadResult result = ObjectConvertUtil.convertObject(e, CashOutDownloadResult.class);
            if (null != result) {
                result.setGmtCreate(DateUtils.formatYMDHMSStr(e.getGmtCreate()));
                result.setStatus(CashOutOrderStatus.getDesc(e.getStatus()));
                result.setAmount(FormatUtils.fenToYuan(e.getAmount()));
                UserInfo userInfo = userInfoMap.get(e.getUserId());
                if (null != userInfo) {
                    if (Arguments.strNotNull(userInfo.getPayAccount())) {
                        JsonPayAccount pay = JSONObject.parseObject(userInfo.getPayAccount(), JsonPayAccount.class);
                        if (null != pay) {
                            result.setBankCard(pay.getBankCard());
                            result.setBankName(pay.getBankName());
                            result.setUserName(pay.getUserName());
                            result.setBranchName(pay.getBranchName());
                        }
                    }
                }
                results.add(result);
            }
        });
        return results;
    }

    private Map<Integer, UserInfo> getUserInfoMap(List<CashOutOrder> cashOutOrders) {
        List<Integer> userIds = Lists.transform(cashOutOrders, CashOutOrder::getUserId);
        if (userIds.size() == 0) {
            return Maps.newHashMap();
        }
        List<UserInfo> userInfos = userInfoMapper.selectBatchIds(userIds);
        return Maps.uniqueIndex(userInfos, UserInfo::getId);
    }

    private Map<String, Object> getDefault() {
        Map<String, Object> jsonObject = new HashMap<>();
        List<String> extractRuleList = Lists.newArrayList();
        extractRuleList.add("1. 佣金累计满100元可提现");
        extractRuleList.add("2. 提现到账预计48小时内到账，如超过48小时未到账您可联系客服询问详情");
        extractRuleList.add("3. 佣金提现每天只能申请提现一次");
        extractRuleList.add("4. 佣金提现需要绑定银行卡");
        jsonObject.put("extractRule", extractRuleList);
        List<String> bankBindList = Lists.newArrayList();
        bankBindList.add("1. 只能绑定一张银行卡,且只支持绑定16-19位银行卡号的国内借记卡");
        bankBindList.add("2. 如何绑定：点击去绑定按钮，输入正确的持卡人、卡号、银行名称、开户支行信息点击确定即可完成绑定");
        bankBindList.add("3. 如何修改：点击修改银行卡按钮，输入正确的持卡人、卡号、银行名称、开户支行信息点击确定即可修改银行卡信息");
        jsonObject.put("bankBindRule", bankBindList);
        List<String> warmPromptList = Lists.newArrayList();
        warmPromptList.add("1. 请务必输入正确的银行卡信息，否则将可能出现提现失败等情况");
        warmPromptList.add("2. 若有其它疑问请联系客服：400-8263595客服时间：9：00  -  17:00");
        jsonObject.put("warmPrompt", warmPromptList);
        return jsonObject;
    }

}
